package za.org.jcicada.genss.sensor.impl;

import java.util.Observable;

import za.org.jcicada.genss.sensor.ISamplingStrategy;
import za.org.jcicada.genss.sensor.ISensor;
import za.org.jcicada.genss.sensor.ISensorValue;
import za.org.jcicada.genss.sensor.SensorURN;

/**
 * Abstract base class implementation for sampling strategies. It keeps a handle
 * to the sensor and listener for events and updates the listener when it is
 * notified by the derived sampling strategy.
 * @author rcrida
 */
public abstract class StrategyBase implements ISamplingStrategy {

	private static final long serialVersionUID = 1L;

	/**
     * The URI of the sensor that this strategy will sample.
     */
    private SensorURN sensorURN;
    
    /**
     * The sensor object that will be sampled.
     */
    private ISensor sensor;
    
    /**
     * Handle to a callback object to notify of samples of the sensor.
     */
    private IListener listener;
    
    /**
     * Constructor
     * @param sensorURN the sensor URI
     */
    public StrategyBase(SensorURN sensorURN) {
        this.sensorURN = sensorURN;
    }
    
    public SensorURN getSensorURN() {
        return sensorURN;
    }
    
    public ISensor getSensor() {
        return sensor;
    }
    
    public boolean attachToSensor(ISensor sensor) {
        if (this.sensor == sensor) {
            return true;
        }
        detachFromSensor();
        this.sensor = sensor;
        this.sensor.addObserver(this);
        return true;
    }
    
    public void detachFromSensor() {
        if (sensor != null) {
            sensor.deleteObserver(this);
            sensor = null;
        }
    }
    
    public void setListener(IListener listener) {
        this.listener = listener;
    }

    /**
     * Default update handler which does nothing when a sensor informs it of a
     * change.
     */
    public void update(Observable o, Object arg) {
    	if (arg == null)
    		throw new IllegalArgumentException("update arg may not be null");
    	if (arg instanceof ISensorValue) {
    		updateValue(o, (ISensorValue) arg);
    	}
    	else
    		notifySample(arg);
    }
    
    protected void updateValue(Observable o, ISensorValue value) {
    }

    /**
     * Default periodic behaviour does nothing. This is overridden in the 
     * StrategyPeriodic class.
     */
    public long periodic(long time) {
        return 0;
    }

    /**
     * Called to notify that a sample has taken place. The sensor object may be
     * the actual sensor object or a clone. 
     * @param value the sampled sensor value details
     */
    public void notifySample(Object value) {
        if (listener != null) {
            listener.update(sensorURN, value);
        }
    }

}
